﻿using System;
using System.Collections.Generic;
using System.Text;
using SdmxMl.Manager;
using SdmxMl.Structure;
using SdmxMl.Common;

namespace SdmxDiff
{
    public class AnnotationDiff
    {
        private AnnotationList annListOld;
        private AnnotationList annListNew;
        private Artefact art;
        private string subject;

        public AnnotationDiff(Artefact a, string subj, AnnotationList anOld, AnnotationList anNew)
        {
            art = a;
            subject = subj;
            annListNew = anNew;
            annListOld = anOld;
        }

        public void DiffOld(ReportDiff report)
        {
            AnnotationList annDiff = new AnnotationList();

            // New annot flag
            if (annListNew.Count > annListOld.Count)
                report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), art.FullIdent, subject, "Annotations", "Annotation added ( " 
                    + (annListNew.Count - annListOld.Count).ToString() + ")" } );

            // deleted annot flag
            if (annListNew.Count < annListOld.Count)
                report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), art.FullIdent, subject, "Annotations", "Annotation Removed ( " 
                    + (annListOld.Count - annListNew.Count).ToString() + ")" } );

            // make a list of annotation not similar to old list
            foreach (Annotation a in annListNew)
            {
                bool same = false;
                foreach (Annotation ao in annListOld)
                {
                    if (a.SameAs(ao))
                    {
                        same = true;
                        break;
                    }
                }
                if (same == false)
                    annDiff.Add(a);
            }

            foreach (Annotation a in annDiff)
            {
                StringBuilder sb = new StringBuilder("Change: ");
                sb.Append("Type: ").Append(a.Type).Append(" - Titel: ").Append(a.Title).Append(" - Text: ").Append(a.Text.GetFirst());
                report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), art.FullIdent, subject, "Annotations", sb.ToString() });
            }

        }

        public void Diff(ReportDiff report)
        {
            AnnotationListDiff anld = new AnnotationListDiff(annListOld, annListNew);
            DicoTypeDiff dicoDiff = anld.DicoDiff;
            if (dicoDiff.HasDiff)
            {
                // New annot type
                List<string> addedTypes = dicoDiff.AddedTypes;
                foreach (string type in addedTypes)
                    report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), art.FullIdent, subject, "Annotations", "New Type " + type
                    });
                // Deleted annot type
                List<string> removedTypes = dicoDiff.RemovedTypes;
                foreach (string type in removedTypes)
                    report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), art.FullIdent, subject, "Annotations", "Removed Type " + type
                    });
                // Type count removed or added
                foreach (KeyValuePair<string, OldNewTypeList> kvp in dicoDiff)
                {
                    OldNewTypeList ontl = kvp.Value;
                    if (ontl.anListNew.Count > 0 && ontl.anListOld.Count > 0)
                    {
                        int nb = ontl.anListNew.Count - ontl.anListOld.Count;
                        if (nb > 0)
                        {
                            report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), 
                                art.FullIdent, subject, "Annotations", nb.ToString() +" Added of Type " + kvp.Key});
                        }
                        else if (nb < 0)
                        {
                            report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), 
                                art.FullIdent, subject, "Annotations", Math.Abs(nb).ToString() +" Removed of Type " + kvp.Key});
                        }

                        // non matching, up to diffCount
                        int diffScanCount = Math.Min(ontl.anListNew.Count, ontl.anListOld.Count);
                        List<Annotation> anList = new List<Annotation>();
                        List<Annotation> anListOld = new List<Annotation>();

                        // store old list of non matching
                        foreach (AnnotationMatch ano in ontl.anListOld)
                            if (ano.match == false)
                                anListOld.Add(ano.Annot);

                        // store new list of non matching, correct diff count
                        foreach (AnnotationMatch anm in ontl.anListNew)
                        {
                            if (anm.match)
                                --diffScanCount;
                            else
                                anList.Add(anm.Annot);
                        }
                        // Now details differences for diffscancount, we assume newer are at end
                        int curDiff = 0;
                        while (diffScanCount > 0)
                        {
                            Annotation newAnnot = anList[curDiff];
                            Annotation oldAnnot = anListOld[curDiff];
                            bool titleDiff = string.IsNullOrEmpty(newAnnot.Title) != string.IsNullOrEmpty(oldAnnot.Title);
                            bool urnDiff = newAnnot.Url != oldAnnot.Url;
                            MultilangDiff mld = new MultilangDiff(newAnnot.Text, oldAnnot.Text);

                            StringBuilder sb = new StringBuilder();
                            if (string.IsNullOrEmpty(mld.DiffComment) == false)
                            {
                                sb.Append(mld.DiffComment);
                            }
                            if (titleDiff)
                            {
                                if (sb.Length > 0)
                                    sb.Append(" ,");
                                sb.Append("Title changed");
                            }
                            if (urnDiff)
                            {
                                if (sb.Length > 0)
                                    sb.Append(" ,");
                                sb.Append("Urn changed");
                            }
                            if (sb.Length > 0)
                                report.ReportTable.Rows.Add(new object[] { art.ArType.ToString(), 
                                art.FullIdent, subject, "Annotations", kvp.Key + " " + sb.ToString(), 
                                newAnnot.Text, oldAnnot.Text});

                            ++curDiff;
                            --diffScanCount;
                        }


                    }
                }

            }
        }

    }
}
